﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using TheWorldsWorst.ApiWrapper;
using TheWorldsWorst.ApiWrapper.Model;

namespace StackOverflow.Api.ExampleApp.Views.Shared
{
    public class Format
    {
        public static String Header(String current)
        {
            String questionsClass = (current == "questions") ? " class='youarehere'" : "";
            String tagsClass = (current == "tags")? " class='youarehere'" : "";
            String usersClass = (current == "users") ? " class='youarehere'" : "";
            String deckClass = (current == "deck") ? " class='youarehere'" : "";
            String unansweredClass = (current == "unanswered") ? " class='youarehere'" : "";

            return String.Format(@"
            <div id='hmenus'>
                <div class='nav'>
                    <ul>
                        <li{0}><a href='/'>Questions</a></li>
                        <li{1}><a href='/listtags'>Tags</a></li>
                        <li{2}><a href='/users'>Users</a></li>
                        <li{3}><a href='/deck'>Deck</a></li>
                        <li{4}><a href='/unanswered'>Unanswered</a></li>
                    </ul>
                </div>
                <div class='nav' style='float:right'>
                    <ul>
                        <li style='margin-right:0px' >
                            <a href='http://dev.meta.stackoverflow.com/questions/34594/overall-api-method-list'>Dev Meta</a>
                        </li>
                    </ul>
                </div>
            </div>",
                   questionsClass, tagsClass, usersClass, deckClass, unansweredClass);
        }

        public static String Pager(String path, int pageNum, int pageSize, bool beforeLastPage)
        {
            String separator = path.Contains("?") ? "&amp;" : "?";
            String class15 = (pageSize == 15) ? "current " : "";
            String class30 = (pageSize == 30) ? "current " : "";
            String class50 = (pageSize == 50) ? "current " : "";
            String prevDisplay = (pageNum > 1) ? "" : "style='display:none'";
            String nextDisplay = (beforeLastPage) ? "" : "style='display:none'";

            return String.Format(@"
            <div style='float: right;'>
                <div class='page-sizer'>
                    <a href='{0}{1}pagesize=15' title='show 15 items per page' class='{2}page-numbers'>15</a>
                    <a href='{0}{1}pagesize=30' title='show 30 items per page' class='{3}page-numbers'>30</a>
                    <a href='{0}{1}pagesize=50' title='show 50 items per page' class='{4}page-numbers'>50</a>
                    <span class='page-numbers desc'>per page</span>
                </div> 
            </div>        

            <div style='float: left;'>
                <div class='pager'>
                    <a href='{0}{1}pageNum={5}&amp;pageSize={6}' title='go to page {5}' rel='prev' {7}><span class='page-numbers prev'>prev </span></a>
                    <span class='page-numbers current'>{8}</span>
                    <a href='{0}{1}pageNum={9}&amp;pageSize={6}' title='go to page {9}' rel='next' {10}><span class='page-numbers next'> next</span></a>
                </div>
            </div>",
                path, separator, class15, class30, class50, pageNum - 1, pageSize, prevDisplay, pageNum, pageNum + 1, nextDisplay);

        }

        public static String Tags(IEnumerable<string> tags, bool separateLines)
        {
            StringBuilder s = new StringBuilder();
            foreach (String tag in tags)
                s.AppendFormat("<a href=\"/tags/{2}\" class=\"post-tag\" title=\"show questions tagged '{0}'\" rel=\"tag\">{0}</a>{1}", tag, (separateLines?"<br/>":" "), System.Web.HttpUtility.UrlEncode(tag));
            return s.ToString();
        }

        public static String QuestionListing(Question q)
        {
            String answerClass = (q.TotalAnswers == 0) ? "unanswered" : (q.AcceptedAnswer == null) ? "answered" : "answered-accepted";
            String answerPlurality = (q.TotalAnswers != 1) ? "s" : "";
            String viewPlurality = (q.ViewCount != 1) ? "s" : "";

            String bountyIndicator = (q.BountyClosesDate != null) ? String.Format("<div class='bounty-indicator' title='this question has an open bounty worth {0} reputation'>+{0}</div>", q.BountyAmount) : "";

            String byline;
            if (q.IsCommunityOwned)
                byline = String.Format("<div class='user-info'><div class='user-details'><span class='community-wiki' title='This post is community owned as of ###DATE###. Votes do not generate reputation, and it can be edited by users with 100 rep'>community wiki</span></div><br><div class='user-details'><a id='history-{0}' href='javascript:return false;' title='show revision history for this post'>{1}</a></div></div>", q.QuestionId, q.Owner.DisplayName);
            else
                byline = String.Format("<div class='user-info'><div class='user-action-time'>asked <span title='{0}' class='relativetime'>{1}</span></div><div class='user-gravatar32'><a href='/users/{2}'><img src='{3}' alt='' height='32' width='32'></a></div><div class='user-details'><a href='/users/{2}'>{4}</a><br><span class='reputation-score' title='reputation score'>&nbsp;</span></span></span></div></div>", Zulu(q.CreationDate), Ago(q.CreationDate), q.Owner.UserId, q.Owner.Gravatar, q.Owner.DisplayName);


            return String.Format(@"
            <div class='question-summary' id='question-summary-{0}'>
                <div class='statscontainer'>
                    <div class='statsarrow'></div>
                    <div class='stats'>
                        <div class='vote'>
                            <div class='votes'>
                                <span class='vote-count-post'><strong>{1}</strong></span>
                                <div class='viewcount'>votes</div>
                            </div>
                        </div>
                        <div class='status {2}'>
                            <strong>{3}</strong>answer{4}
                        </div>
                    </div>
                    <div class='views'>{5} view{6}</div>
                </div>
                <div class='summary'>
                    {11}<h3><a href='/question/{0}' class='question-hyperlink'>{7}</a></h3>
                    <div class='excerpt'>
                        {8}
                        <div class='started'>
                            {12}
                        </div>  
                        <div class='tags t-{9}'>
                            {10}
                        </div>
                    </div>
                </div>
            </div>",
                   q.QuestionId, q.Score, answerClass, q.TotalAnswers, answerPlurality, q.ViewCount, viewPlurality, q.Title, Abbr(q.Body), String.Join(" t-", q.Tags.ToArray()), Tags(q.Tags, false), bountyIndicator, byline);
        }

        public static String Question(Question q)
        {
            String edited = "";
            String sig = "";

            if (q.LastEditDate != null)
            {
                if (q.IsCommunityOwned)
                    edited = String.Format(@"<td align='right' class='post-signature'>
				    <div class='user-info'><div class='user-action-time'>edited <a href='javascript:return false;' title='show all edits to this post'><span title='{0}' class='relativetime'>{1}</span></a></div></div>
			    </td>", Zulu((DateTime)q.LastEditDate), Ago((DateTime)q.LastEditDate));
                else
                    edited = String.Format(@"<td align='right' class='post-signature'>
				    <div class='user-info'><div class='user-action-time'>edited <a href='javascript:return false;' title='show all edits to this post'><span title='{0}' class='relativetime'>{1}</span></a></div><div class='user-gravatar32'></div><div class='user-details'><br></div></div>
			    </td>", Zulu((DateTime)q.LastEditDate), Ago((DateTime)q.LastEditDate));
            }

            if (q.IsCommunityOwned)
                sig = String.Format(@"<td class='post-signature'>
		        <div class='user-info'><div class='user-details'><span class='community-wiki' title='This post is community owned as of ??????????. Votes do not generate reputation, and it can be edited by users with 100 rep'>community wiki</span></div><br><div class='user-details'><a id='history-{0}' href='javascript:return false;' title='show revision history for this post'>{1}</a></div></div>
		    </td>", q.QuestionId, q.Owner.DisplayName);
            else
            {
                string gravatar = string.Empty;
                if (q.Owner.UserId.HasValue)
                    gravatar = ApiProxy.GetUserFor(q.Owner.UserId.Value).Gravatar;

                sig = String.Format(@"<td class='post-signature owner'>
			    <div class='user-info'><div class='user-action-time'>asked <span title='{0}' class='relativetime'>{1}</span></div><div class='user-gravatar32'><a href='/users/{2}'><img src='{4}' alt='' width='32' height='32'></a></div><div class='user-details'><a href='/users/{2}'>{3}</a><br><span class='reputation-score' title='reputation score'></span></div></div>
		    </td>", Zulu(q.CreationDate), Ago(q.CreationDate), q.Owner.UserId, q.Owner.DisplayName, gravatar);
            }


            return String.Format(@"<table>
            <tr>
	            <td class='votecell'>
		            <div class='vote'>
			            <input type='hidden' value='{0}'>
			            <img class='vote-up'
				            src='/content/img/vote-arrow-up.png'
				            width='40' height='25'
				            alt='vote up' title='This question is useful and clear (click again to undo)'>
			            <span class='vote-count-post'{7}>
				            {1}
			            </span>
			            <img class='vote-down'
				            src='/content/img/vote-arrow-down.png'
				            width='40' height='25'
				            alt='vote down' title='This question is unclear or not useful (click again to undo)'>
			            <img class='vote-favorite' 
				            src='/content/img/vote-favorite-off.png'
				            width='32' height='31'
				            alt='star' title='This is a favorite question (click again to undo)'>
			            <div class='favoritecount'><b>{2}</b></div>    
		            </div>
	            </td>
            <td>
	            <div>
                    <div class='post-text'>
                        {3}
                    </div>            
                    <div class='post-taglist'>
                        {4}
                    </div>
                    <table class='fw'>
			            <tr>
			            <td class='vt'>
				            <div class='post-menu'><a href='javascript:return false;' title='edit this post, or roll it back to a previous revision'>edit</a><span class='lsep'>|</span><a id='flag-post-{0}' title='flag this post for serious problems'>flag</a></div>
			            </td>
			            {5}
			            {6}
			            </tr>
                    </table>
                </div>
            </td>
            </tr>
            {8}
            </table>",
                     q.QuestionId, q.Score, ((q.FavoriteCount != 0)? q.FavoriteCount.ToString() : ""), q.Body, Tags(q.Tags, false), edited, sig, ((q.Score > 99)? " style='font-size: 200%'" : ""), Comments(q.Comments, q.QuestionId, q.Owner.UserId.Value));

        }

        public static String Answer(Answer a, long QOwnerId)
        {
            String edited = "";
            String sig = "";
            String accepted = a.IsAccepted ? "<img src='/content/img/vote-accepted-on.png' class='vote-accepted' style='cursor:default' width='30' height='31' alt='check' title='The question owner accepted this as the best answer ###DATE###'>" : "";

            if (a.LastEditDate != null)
            {
                if(a.IsCommunityOwned)
                    edited = String.Format(@"<td align='right' class='post-signature'>
				    <div class='user-info'><div class='user-action-time'>edited <a href='javascript:return false;' title='show all edits to this post'><span title='{0}' class='relativetime'>{1}</span></a></div></div>
			    </td>", Zulu((DateTime)a.LastEditDate), Ago((DateTime)a.LastEditDate));

                else
                    edited = String.Format(@"<td align='right' class='post-signature'>
				    <div class='user-info'><div class='user-action-time'>edited <a href='javascript:return false;' title='show all edits to this post'><span title='{0}' class='relativetime'>{1}</span></a></div><div class='user-gravatar32'></div><div class='user-details'><br></div></div>
			    </td>", Zulu((DateTime)a.LastEditDate), Ago((DateTime)a.LastEditDate));
            }

            if (a.IsCommunityOwned)
                sig = String.Format(@"<td class='post-signature'>
		        <div class='user-info'><div class='user-details'><span class='community-wiki' title='This post is community owned as of ??????????. Votes do not generate reputation, and it can be edited by users with 100 rep'>community wiki</span></div><br><div class='user-details'><a id='history-{0}' href='javascript:return false;' title='show revision history for this post'>{1}</a></div></div>
		    </td>", a.AnswerId, a.Owner.DisplayName);
            else
            {
                string gravatar = string.Empty;
                
                if(a.Owner.UserId.HasValue)
                    gravatar = ApiProxy.GetUserFor(a.Owner.UserId.Value).Gravatar;
                sig = String.Format(@"<td class='post-signature{0}'>
			    <div class='user-info'><div class='user-action-time'>answered <span title='{1}' class='relativetime'>{2}</span></div><div class='user-gravatar32'><a href='/users/{3}'><img src='{5}' alt='' width='32' height='32'></a></div><div class='user-details'><a href='/users/{3}'>{4}</a><br><span class='reputation-score' title='reputation score'></span></div></div>
		    </td>", ((a.Owner.UserId == QOwnerId) ? " owner" : ""), Zulu(a.CreationDate), Ago(a.CreationDate), a.Owner.UserId, a.Owner.DisplayName, gravatar);
            }

            return String.Format(@"<a name='{0}'></a>
            <div id='answer-{0}' class='answer '>
	            <table>
                    <tr>
                    <td class='votecell'>
			            <div class='vote'>
			            <input type='hidden' value='{0}'>
			            <img class='vote-up'
			            src='/content/img/vote-arrow-up.png'
			            width='40' height='25'
			            alt='vote up' title='This answer is useful (click again to undo)'>
			            <span class='vote-count-post'{6}>
				            {1}
			            </span>
			            <img class='vote-down'
			            src='/content/img/vote-arrow-down.png'
			            width='40' height='25'
			            alt='vote down' title='This answer is not useful (click again to undo)'>
                        {8}
			            </div>
                    </td>
                    <td>
                        <div class='post-text'>
				            {2}
			            </div>
                        <table class='fw'>
				            <tr>
					            <td class='vt'>
						            <div class='post-menu'><a href='/question/{3}#{0}' title='permalink to this answer'>link</a><span class='lsep'>|</span><a href='javascript:return false;' title='edit this post, or roll it back to a previous revision'>edit</a><span class='lsep'>|</span><a id='flag-post-{0}' title='flag this post for serious problems'>flag</a></div>                
					            </td>
					            {4}
					            {5}            
				            </tr>
                        </table>
                    </td>
                    </tr>
                    {7}    
	            </table>
            </div>",
                a.AnswerId, a.Score, a.Body, a.QuestionId, edited, sig, ((a.Score > 99) ? " style='font-size: 200%'" : ""), Comments(a.Comments, a.AnswerId, QOwnerId), accepted);
        }

        public static String Comments(IEnumerable<Comment> comments, long parentId, long QOwnerId)
        {
            StringBuilder s = new StringBuilder();
            s.AppendFormat(@"<tr>
            <td class='votecell'></td>
            <td>
                <div id='comments-{0}' class='comments{1}'>
		            <table>
                    <tbody>",
                            parentId, ((comments.Count() == 0)? " dno" : ""));

            foreach (Comment c in comments)
            {
                String score = (c.VoteCount == 0) ? "&nbsp;" : String.Format("<span title='number of \\'great comment\\' votes received' class='cool'>{0}</span>", c.VoteCount);
                String edited = (c.EditCount == null || c.EditCount == 0) ? "" : "<img class='comment-edited' src='/content/img/comment-edited.png' width='14' height='14' alt='' title='this comment was edited'>";

                s.AppendFormat(@"<tr id='comment-{0}' class='comment'>
				<td class='comment-actions'>
					<table><tbody><tr>
						<td class='comment-score'>
							{1}
						</td>
						<td>
							<img class='comment-up' src='/content/img/comment-up.png' width='14' height='14' title='this is a great comment'>
						</td></tr>
					<tr>
						<td>&nbsp;</td>
						<td>
							<img class='comment-flag' src='/content/img/comment-flag.png' width='14' height='14' title='flag this comment as noise, offensive, or spam'>
						</td>
					</tr></tbody></table>
				</td>
				<td class='comment-text'><div>
				 {2}&nbsp;&ndash;&nbsp;<a href='/users/{3}' title='???' class='comment-user{8}'>{4}</a> <span class='comment-date'><span title='{5}'>{6}</span></span>{7}</div></td>
			</tr>",
                  c.CommentId, score, c.Body, c.Owner.UserId, c.Owner.DisplayName, Zulu(c.CreationDate), Ago(c.CreationDate), edited, ((c.Owner.UserId == QOwnerId)?" owner":""));
            }

            s.AppendFormat(@"</tbody>
                    <tfoot>
                        <tr>
                            <td></td>
                            <td class='comment-form'><form id='add-comment-{0}'></form></td>
                        </tr>
                    </tfoot>
                    </table>
                </div>
                <a id='comments-link-{0}' class='comments-link' title='add a comment to this post'>add comment</a>
            </td>
            </tr>",
                  parentId);

            return s.ToString();
        }

        public static String QuestionSidebar(Question q)
        {
            String viewedPlurality = (q.ViewCount!=1)?"s":"";
            String latestActivity = "";
            if (q.LastActivityDate != null)
                latestActivity =String.Format("<p class='label-key'>latest activity</p><p class='label-value' title='{0}'>{1}</p>", Zulu((DateTime)q.LastActivityDate), Ago((DateTime)q.LastActivityDate)) ;

            return String.Format(@"
            <div class='module' style='padding-bottom:1px'>
	            <p class='label-key'>tagged</p>
	            <div class='tagged'>
		            {0}
	            </div> 
	            <p class='label-key'>asked</p>
	            <p class='label-value' title='{1}'>{2}</p>
	            <p class='label-key'>viewed</p>
	            <p class='label-value'>{3:#,##0} time{4}</p>
	            {5}
            </div>",
                   Tags(q.Tags,true), Zulu(q.CreationDate), Ago(q.CreationDate), q.ViewCount, viewedPlurality, latestActivity);
        }

        public static String UserListing(User u)
        {
            string badges = "<span title='{0} {3} badge{1}'><span class='badge{2}'>●</span><span class='badgecount'>{0}</span></span>";

            string moderator = (u.UserType == UserType.Moderator) ? "<span class='mod-flair' title='moderator'>♦</span>" : "";
            string golds = (u.GoldBadgeCount > 0) ? String.Format(badges, u.GoldBadgeCount, (u.GoldBadgeCount > 1 ? "s" : ""), "1", "gold") : "";
            string silvers = (u.SilverBadgeCount > 0) ? String.Format(badges, u.SilverBadgeCount, (u.SilverBadgeCount > 1 ? "s" : ""), "2", "silver") : "";
            string bronzes = (u.BronzeBadgeCount > 0) ? String.Format(badges, u.BronzeBadgeCount, (u.BronzeBadgeCount > 1 ? "s" : ""), "3", "bronze") : "";
            
            return String.Format(@"
            <div class='user-info'>
                <div class='user-action-time'> </div>
                <div class='user-gravatar32'>
                    <a href='/users/{0}/{1}'>
                        <img src='{2}&amp;s=32' height='32' width='32' alt=''></a>
                </div>
                <div class='user-details'>
                    <a href='/users/{0}/{1}' >{1}</a>{4}<br>
                    <span class='reputation-score' title='reputation score'>{3}</span>
                    {5}{6}{7}
                </div>
            </div>",
                   u.UserId, u.Name, u.Gravatar, TruncateRep(u.Reputation), moderator, golds, silvers, bronzes);
        }

        public static String TruncateRep(int reputation)
        {
            if (reputation < 10000)
                return reputation.ToString("#,###");
            else
                // REVIEW: don't know if this should truncate or round
                return ((double)reputation / 1000.0).ToString("#.#k");
        }

        public static String Ago(DateTime d)
        {
            TimeSpan ts = DateTime.Now.ToUniversalTime() - d;
            if (ts.Days > 334)
                return d.ToString("MMM d \\'yy a\\t H:mm");
            else if (ts.Days > 2)
                return d.ToString("MMM d a\\t H:mm");
            else if (ts.Days == 2)
                return String.Format("2 days ago at {0:H:mm}", d);
            else if (ts.Days == 1)
                return String.Format("yesterday at {0:H:mm}", d);
            else if (ts.Hours >= 1)
                return String.Format("{0} hour{1} ago", ts.Hours, (ts.Hours != 1) ? "s" : "");
            else if (ts.Minutes >= 1)
                return String.Format("{0} min{1} ago", ts.Minutes, (ts.Minutes != 1) ? "s" : "");
            else if (ts.Minutes < 1)
                return String.Format("{0} sec{1} ago", ts.Seconds, (ts.Seconds != 1) ? "s" : "");
            else
                return "??? " + d.ToLongDateString();
        }

        public static String Zulu(DateTime d)
        {
            return d.ToString("yyyy-MM-dd HH:mm:ssZ");
        }

        public static String Abbr(String body)
        {
            if (body == null)
                return "<br/><br/>";
            body = new Regex("<[^>]+?>").Replace(body, "");
            if (body.Length < 200)
                return body;
            else
            {
                int pos = body.IndexOf(" ", 192);
                if(pos >= 192)
                    return body.Substring(0, pos) + "&hellip;";
                else
                    return body.Substring(0, 192) + "&hellip;";
            }
        }
    }
}
